package com.tencent.basic.service.impl;

import com.tencent.basic.constant.VerifyConstants;
import com.tencent.basic.dto.SmsCodeDto;
import com.tencent.basic.exception.BusinessException;
import com.tencent.basic.service.IVerifyCodeService;
import com.tencent.basic.util.StrUtils;
import com.tencent.basic.util.VerifyCodeUtils;
import com.tencent.user.domain.User;
import com.tencent.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    /**
     * 获取图形验证码的业务
     * @param key
     * @return
     */
    @Override
    public String getImageCode(String key) {
        // 1. 判断key值是否为空
        if(key == null) {
            throw new BusinessException("key无效");
        }
        // 2. 获取随机验证码
        String code = StrUtils.getComplexRandomString(4);// 长度为4 包含英文的随机验证码

        // 3. 将验证码放进redis中  设置五分钟过期
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);

        // 4. 将随机验证码 转换成图形验证码
        String verifyCode = VerifyCodeUtils.verifyCode(115, 42, code);

        return verifyCode;
    }

    /**
     * 发送手机验证码
     * @param smsCodeDto
     */
    @Override
    public void sendSmsCode(SmsCodeDto smsCodeDto) {
        // 先拿出对象里的数据
        String phone = smsCodeDto.getPhone();
        String imageCode = smsCodeDto.getImageCode();
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        // 1. 判断空值
        if (StringUtils.isEmpty(phone.trim())) {
            throw new BusinessException("手机号不能为空！");
        }
        if (StringUtils.isEmpty(imageCode)) {
            throw new BusinessException("图形验证码不能为空！");
        }
        if (StringUtils.isEmpty(imageCodeKey)) {
            throw new BusinessException("请重新获取图形验证码！");
        }

        // 2. 校验手机号是否已经注册
        User user = userMapper.loadByPhone(phone);
        if (user != null) { // 存在该手机号的用户
            throw new BusinessException("该手机号已被注册，忘记密码请联系管理员");
        }

        // 3. 判断图形验证码是否过期 - 通过key从redis获取value 没有就过期了
        // 这里不能toStirng 如果为空 toString就空指针了
        Object redisImageCode = redisTemplate.opsForValue().get(imageCodeKey);
        if (redisImageCode == null) {
            throw new BusinessException("图形验证码已过期");
        }

        // 4. 判断图形验证码是否正确 - 忽略大小写
        // equals不能Object 这里可以toStirng - 上面已经判断过不为null才会走到这一步 - 所以不用担心空指针
        if (!imageCode.equalsIgnoreCase(redisImageCode.toString())) {
            throw new BusinessException("图形验证码错误");
        }

        // redis存值格式  -  key[register:18708146200] - value[code:time]验证码:时间戳
        // 5. 获取手机验证码 判断是否过期
        String code = null; // 用于装手机验证码

        // 从redis中获取手机验证码 - 两种情况
        Object redisPhoneCode = redisTemplate.opsForValue().get(VerifyConstants.REGISTER_PREFIX + phone);
        if (redisPhoneCode == null) { // 第一次获取 or 已经过期了
            // 就生成一个新的手机验证码
            code = StrUtils.getComplexRandomString(6) + ":" + System.currentTimeMillis();
        } else {
            // 转换成字符串以 : 分割字符串 前面是验证码 后面是时间戳
            long redisTime = Long.parseLong(redisPhoneCode.toString().split(":")[1]);
            String redisCode = redisPhoneCode.toString().split(":")[0];
            long nowTime = System.currentTimeMillis();
            // 没有过期 存在code值 那么又分为两种情况
            if ((nowTime - redisTime)< (1 * 60 * 1000)) { // 1. 上一条发送时间不超过一分钟重发时间
                throw new BusinessException("请勿重复获取验证码");
            }
            // 2. 已经过了一分钟重发时间
            code = redisCode + ":" + System.currentTimeMillis();
        }
        // 6. 保存验证码到redis 并设置有效时间3分钟
        redisTemplate.opsForValue().set(VerifyConstants.REGISTER_PREFIX + phone, code, 3, TimeUnit.MINUTES);

        // 7. 发送手机短信
        // SmsUtil.sendSms(phone, "您的手机验证码为" + redisPhoneCode.toString().split(":")[0] + "请在3分钟内使用");
        System.out.println("您的手机验证码为:" + code.split(":")[0] + ",请在3分钟内使用");
        System.out.println(code);
    }

    /**
     * 检查邮箱注册的图形验证码
     * @param smsCodeDto
     */
    @Override
    public void checkEmailCode(SmsCodeDto smsCodeDto) {
        String imageCode = smsCodeDto.getImageCode();
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        if (StringUtils.isEmpty(imageCode)) {
            throw new BusinessException("图形验证码不能为空！");
        }
        if (StringUtils.isEmpty(imageCodeKey)) {
            throw new BusinessException("请重新获取图形验证码！");
        }

        // 1. 判断图形验证码是否过期 - 通过key从redis获取value 没有就过期了
        // 这里不能toStirng 如果为空 toString就空指针了
        Object redisImageCode = redisTemplate.opsForValue().get(imageCodeKey);
        if (redisImageCode == null) {
            throw new BusinessException("图形验证码已过期");
        }

        // 2. 判断图形验证码是否正确 - 忽略大小写
        // equals不能Object 这里可以toStirng - 上面已经判断过不为null才会走到这一步 - 所以不用担心空指针
        if (!imageCode.equalsIgnoreCase(redisImageCode.toString())) {
            throw new BusinessException("图形验证码错误");
        }
    }

    /**
     * 微信扫码登录手机号绑定获取手机验证码
     * @param smsCodeDto
     */
    @Override
    public void binderSmsCode(SmsCodeDto smsCodeDto) {
        // 先拿出对象里的数据
        String phone = smsCodeDto.getPhone();

        // 1. 判断空值
        if (StringUtils.isEmpty(phone.trim())) {
            throw new BusinessException("手机号不能为空！");
        }

        // redis存值格式  -  key[binder:18708146200] - value[code:time]验证码:时间戳
        // 5. 获取手机验证码 判断是否过期
        String code; // 用于装手机验证码 初始null

        // 从redis中获取手机验证码 - 两种情况
        Object redisPhoneCode = redisTemplate.opsForValue().get(VerifyConstants.BINDER_PREFIX + phone);
        if (redisPhoneCode == null) { // 第一次获取 or 已经过期了
            // 就生成一个新的手机验证码
            code = StrUtils.getComplexRandomString(6) + ":" + System.currentTimeMillis();
        } else {
            // 转换成字符串以 : 分割字符串 前面是验证码 后面是时间戳
            long redisTime = Long.parseLong(redisPhoneCode.toString().split(":")[1]);
            String redisCode = redisPhoneCode.toString().split(":")[0];
            long nowTime = System.currentTimeMillis();
            // 没有过期 存在code值 那么又分为两种情况
            if ((nowTime - redisTime)< (1 * 60 * 1000)) { // 1. 上一条发送时间不超过一分钟重发时间
                throw new BusinessException("请勿重复获取验证码");
            }
            // 2. 已经过了一分钟重发时间
            code = redisCode + ":" + System.currentTimeMillis();
        }
        // 6. 保存验证码到redis 并设置有效时间3分钟
        redisTemplate.opsForValue().set(VerifyConstants.BINDER_PREFIX + phone, code, 3, TimeUnit.MINUTES);

        // 7. 发送手机短信
        // SmsUtil.sendSms(phone, "您的手机验证码为" + redisPhoneCode.toString().split(":")[0] + "请在3分钟内使用");
        System.out.println("您的手机验证码为:" + code.split(":")[0] + ",请在3分钟内使用");
        System.out.println(code);
    }
}
